﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Simple.Common.Authentication;
using Simple.Services.System;
using Simple.Services.System.FileInfo;
using Simple.Services.System.FileInfo.Models;

namespace Simple.Services
{
    /// <summary>
    /// 亲子任务
    /// </summary>
    public class ParentChildTasksService : BusinessBaseService
    {
        private readonly SimpleDbContext _context;
        private readonly FileInfoService _fileInfoService;

        public ParentChildTasksService(ISimpleService services,
            SimpleDbContext context,
            FileInfoService fileInfoService) : base(services)
        {
            _context = context;
            _fileInfoService = fileInfoService;
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PageResultModel<ParentChildTasksDto>> GetPageAsync(ParentChildTasksInputModel input)
        {
            var result = new PageResultModel<ParentChildTasksDto>();
            var query = await OrganizationFilter(_context.Set<ParentChildTasks>().Include(c => c.Images));

            // 根据条件查询
            if (input.ClassId.HasValue)
            {
                query = query.Where(u => u.ClassId == input.ClassId);
            }
            if (!string.IsNullOrWhiteSpace(input.Title))
            {
                query = query.Where(u => u.Title.Contains(input.Title));
            }

            // 获取总数量
            result.TotalRows = await query.CountAsync();

            // 分页查询
            var lstParentChildTasks = await query.ToListAsync();
            var lstParentChildTasksDto = MapperHelper.Map<List<ParentChildTasksDto>>(lstParentChildTasks);
            lstParentChildTasksDto = lstParentChildTasksDto.OrderBy(p => p.StateEnum).ThenByDescending(u => u.CreatedTime).Skip((input.PageNo - 1) * input.PageSize).Take(input.PageSize).ToList();
            if (lstParentChildTasksDto != null)
            {
                var lstClass = await _context.Set<SysClasses>().ToListAsync();
                var lstRecode = await _context.Set<ParentChildTasksRecord>().ToListAsync();
                var lstUser = await _context.Set<SysUser>().ToListAsync();
                foreach (var item in lstParentChildTasksDto)
                {
                    var user = lstUser.FirstOrDefault(p => p.Id == item.CreatedUserId);
                    var count = lstRecode.Where(p => p.ParentChildTasksId == item.Id).Select(p => p.CreatedUserId).Distinct().Count();
                    var classes = lstClass.FirstOrDefault(p => p.Id == item.ClassId);
                    if (classes != null)
                    {
                        item.ClassName = classes.Name;
                    }
                    item.Count = count;
                    item.CreatedUser = user?.Name;
                }
            }
            result.Rows = lstParentChildTasksDto;

            result.SetPage(input);
            result.CountTotalPage();

            return result;
        }

        /// <summary>
        /// 预览
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<PreviewDto> Preview(Guid id)
        {
            if (!await (await OrganizationFilter(_context.Set<ParentChildTasks>().AsQueryable())).AnyAsync(p => p.Id == id))
            {
                throw AppResultException.Status500InternalServerError("没有找到该亲子任务");
            }
            var result = new PreviewDto();
            var entity = await (await OrganizationFilter(_context.Set<ParentChildTasks>().Include(p => p.Images))).FirstOrDefaultAsync(p => p.Id == id);
            result.parentChildTasksInfo = MapperHelper.Map<ParentChildTasksInfo>(entity);
            var user = await _context.Set<SysUser>().FirstOrDefaultAsync(p => p.Id == entity.CreatedUserId);
            result.parentChildTasksInfo.CreatedUser = user?.Name;
            var classes = await _context.Set<SysClasses>().FirstOrDefaultAsync(p => p.Id == entity.ClassId);
            result.parentChildTasksInfo.ClassName = classes?.Name;
            var lstRecode = await _context.Set<ParentChildTasksRecord>().Include(p => p.Images).Where(p => p.ParentChildTasksId == entity.Id).ToListAsync();
            result.parentChildTasksInfo.Count = lstRecode.Select(p => p.CreatedUserId).Distinct().Count();

            result.RecodeList = await GetRecodeInfo(id);
            return result;
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<bool> AddAsync(AddTasksInput input)
        {
            if (input.ClassIdList == null || !input.ClassIdList.Any())
            {
                throw AppResultException.Status400BadRequest("参数错误,班级Id为null");
            }
            var lstTask = new List<ParentChildTasks>();
            var images = new List<ParentChildTasksImage>();
            if (input.TaskInfo.ImageIdList != null)
            {
                var files = await _fileInfoService.GetFilesByIdListAsync(input.TaskInfo.ImageIdList);
                images = files?.Select(file => new ParentChildTasksImage { FiledId = file.Id, FileName = file.FileName, FileSize = file.FileSize ?? String.Empty })?.ToList();
            }
            foreach (var item in input.ClassIdList)
            {
                var task = MapperHelper.Map<ParentChildTasks>(input.TaskInfo);
                task.ClassId = item;
                task.Images = images;
                lstTask.Add(task);
            }
            await _context.AddRangeAsync(lstTask);
            var rte = await _context.SaveChangesAsync();
            return rte > 0;
        }

        /// <summary>
        /// 修改
        /// </summary>
        public async Task<bool> UpdateAsync(TasksCreateOrUpdateInput input)
        {
            if (!await _context.Set<ParentChildTasks>().AnyAsync(p => p.Id == input.Id))
            {
                throw AppResultException.Status500InternalServerError("没有找到该亲子计划");
            }
            var task = await _context.Set<ParentChildTasks>().FirstOrDefaultAsync(p => p.Id == input.Id);
            task.Title = input.Title;
            task.TaskIntroduction = input.TaskIntroduction;
            task.StartDate = input.StartDate;
            task.EndDate = input.EndDate;
            task.ClockInDays = input.ClockInDays;
            task.DailyClockInDeadline = input.DailyClockInDeadline;
            task.ClassId = input.ClassId.Value;
            var images = new List<ParentChildTasksImage>();
            if (input.ImageIdList != null)
            {
                var files = await _fileInfoService.GetFilesByIdListAsync(input.ImageIdList);
                images = files?.Select(file => new ParentChildTasksImage { FiledId = file.Id, FileName = file.FileName, FileSize = file.FileSize ?? String.Empty })?.ToList();
            }
            task.Images = images;
            _context.Update(task);
            int ret = await _context.SaveChangesAsync();
            return ret > 0;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public async Task<int> DeleteAsync(IEnumerable<Guid> ids)
        {
            var lstTask = await _context.Set<ParentChildTasks>()
                .Where(u => ids.Contains(u.Id))
                .ToListAsync();

            _context.RemoveRange(lstTask);
            return await _context.SaveChangesAsync();
        }

        /// <summary>
        /// 亲子任务（家长端）
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<List<Tasks>> ParentChildTasksList(TasksListInput input)
        {
            var dateNow = DateTime.Now;
            var childId = _currentUser?.FindClaimValue(SimpleClaimTypes.ChildId);
            var _currentClassId = _currentUser?.FindClaimValue(SimpleClaimTypes.ClassesId);
            var query = _context.Set<ParentChildTasks>().AsQueryable().Include(p => p.RecodeList).Where(p => p.StartDate <= dateNow).Where(p => p.ClassId.ToString() == _currentClassId);
            switch (input.State)
            {
                case ParentChildTasksState.HaveInHand:
                    query = query.Where(p => p.EndDate >= dateNow).Where(p => !p.RecodeList.Any(r => r.CreatedTime.Value.Date == dateNow.Date && r.RelationshipChildrenId.ToString() == childId));
                    break;
                case ParentChildTasksState.Ended:
                    query = query.Where(p => p.EndDate < dateNow);
                    break;
                case ParentChildTasksState.Completed:
                    query = query.Where(p => p.EndDate >= dateNow).Where(p => p.RecodeList.Any(r => r.CreatedTime.Value.Date == dateNow.Date && r.RelationshipChildrenId.ToString() == childId));
                    break;
            }
            var taskList = new List<Tasks>();
            foreach (var item in await query.ToListAsync())
            {
                var daysRemaining = item.EndDate.Value.Date.Subtract(dateNow.Date).Days;
                if (dateNow.Date > item.EndDate.Value.Date) daysRemaining = 0;
                var totle = item.EndDate.Value.Date.Subtract(item.StartDate.Value.Date).Days + 1;
                var allDays = GetAllDay(item.StartDate.Value, item.EndDate.Value);
                var count = item.RecodeList.Where(p => p.RelationshipChildrenId.ToString() == childId).Distinct(new ParentChildTasksRecordByID()).Where(p => allDays.Contains(p.CreatedTime.Value.Date)).Count();
                taskList.Add(new Tasks
                {
                    Id = item.Id,
                    Title = item.Title,
                    Content = $"剩余{daysRemaining}天截止，已完成{count}/{totle}"
                });
            }
            return taskList;
        }

        /// <summary>
        /// 发布
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<bool> Release(ReleaseInput input)
        {
            if (_currentUser == null)
            {
                throw AppResultException.Status409Conflict("登录已过期,请重新登录!");
            }
            var userName = _currentUser?.FindClaimValue(SimpleClaimTypes.UserName);
            var relationshipValue = string.Empty;
            var relationship = _currentUser?.FindClaimValue(SimpleClaimTypes.Relationship);
            var childId = _currentUser?.FindClaimValue(SimpleClaimTypes.ChildId);
            if (!string.IsNullOrWhiteSpace(relationship))
            {
                relationshipValue = EnumHelper.GetDescriptionContent((EnumParentRelationship)Enum.Parse(typeof(EnumParentRelationship), relationship));
            }
            var child = await _context.Set<Childrens>().FirstOrDefaultAsync(p => p.Id.ToString() == childId);
            if (child != null)
            {
                userName = child.Name + relationshipValue;
            }
            var images = new List<ParentChildTasksRecordImage>();
            if (input.ImageIdList != null)
            {
                var files = await _fileInfoService.GetFilesByIdListAsync(input.ImageIdList);
                images = files?.Select(file => new ParentChildTasksRecordImage { FiledId = file.Id, FileName = file.FileName, FileSize = file.FileSize ?? String.Empty })?.ToList();
            }
            var howManyTimes = 1;
            var recode = await _context.Set<ParentChildTasksRecord>().Where(p => p.ParentChildTasksId == input.ParentChildTasksId && p.RelationshipChildrenId == child.Id).OrderByDescending(p => p.HowManyTimes).FirstOrDefaultAsync();
            var entity = new ParentChildTasksRecord
            {
                Content = input.Content,
                CreateUserName = userName,
                Relationship = int.Parse(relationship),
                RelationshipChildrenId = new Guid(childId),
                ParentChildTasksId = input.ParentChildTasksId,
                Images = images,
                HowManyTimes = recode != null ? recode.HowManyTimes++ : 1,
            };
            var record = await _context.AddAsync(entity);
            var ret = await _context.SaveChangesAsync();
            return ret > 0;
        }

        /// <summary>
        /// 详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<TasksDetilDto> TasksDetil(Guid id)
        {
            if (!await _context.Set<ParentChildTasks>().AsQueryable().AnyAsync(p => p.Id == id))
            {
                throw AppResultException.Status500InternalServerError("没有找到该亲子任务");
            }
            var tasks = await _context.Set<ParentChildTasks>().AsQueryable().Include(p => p.Images).Include(p => p.RecodeList).ThenInclude(p => p.Images).FirstOrDefaultAsync(p => p.Id == id);
            var result = new TasksDetilDto()
            {
                Info = new ParentChildTasksInfo()
            };
            result.Info.Id = tasks.Id;
            result.Info.Title = tasks.Title;
            result.Info.CreatedUserId = tasks.CreatedUserId;
            result.Info.CreatedTime = tasks.CreatedTime;
            result.Info.TaskIntroduction = tasks.TaskIntroduction;
            result.Info.StartDate = tasks.StartDate;
            result.Info.EndDate = tasks.EndDate;
            result.Info.DailyClockInDeadline = tasks.DailyClockInDeadline;

            var user = await _context.Set<SysUser>().FirstOrDefaultAsync(p => p.Id == tasks.CreatedUserId);
            var classes = await _context.Set<SysClasses>().FirstOrDefaultAsync(p => p.Id == tasks.ClassId);
            result.Info.CreatedUser = user?.UserName;
            result.Info.ClassName = classes?.Name;

            var childId = _currentUser?.FindClaimValue(SimpleClaimTypes.ChildId);
            var lstRecode = tasks.RecodeList.Where(p => p.RelationshipChildrenId.ToString() == childId).ToList();
            result.MyTasks = GetMyTasks(lstRecode, tasks.StartDate.Value, tasks.EndDate.Value);
            result.RecodeList = await GetRecodeInfo(id);
            return result;
        }

        /// <summary>
        /// 家长任务完成情况
        /// </summary>
        /// <returns></returns>
        public Dictionary<int, bool> GetMyTasks(List<ParentChildTasksRecord> RecodeList, DateTime start, DateTime end)
        {
            var result = new Dictionary<int, bool>();
            if (end <= start) return result;
            var allday = GetAllDay(start, end);
            if (!RecodeList.Any()) return result;
            foreach (var day in allday)
            {
                var isComplete = false;
                if (RecodeList.Any(p => p.CreatedTime.Value.Date == day.Date))
                {
                    isComplete = true;
                }
                result.Add(allday.IndexOf(day) + 1, isComplete);
            }
            return result;
        }

        /// <summary>
        /// 任务统计
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<CompleteStatisticsDto> CompleteStatistics(CompleteStatisticsInput input)
        {
            var tasks = await _context.Set<ParentChildTasks>().AsQueryable().Include(p => p.RecodeList).FirstOrDefaultAsync(p => p.Id == input.ParentChildTasksId);
            if (tasks == null)
            {
                throw AppResultException.Status500InternalServerError("没有找到该亲子任务");
            }
            var allStudent = await _context.Set<Childrens>().AsQueryable().Where(p => p.ClassesId == tasks.ClassId.ToString()).Select(p => new StudentTasksInfo
            {
                StudentId = p.Id,
                StudentName = p.Name,
                ImgId = p.ImgId
            }).ToListAsync();
            var result = new CompleteStatisticsDto() { CompleteStudent = new List<StudentTasksInfo>(), UnfinishedStudents = new List<StudentTasksInfo>() };
            if (!allStudent.Any()) return result;
            var completeStudent = new List<StudentTasksInfo>();
            var unfinishedStudents = new List<StudentTasksInfo>();
            var lstRecode = tasks.RecodeList.OrderBy(p => p.CreatedTime).ToList();
            foreach (var item in allStudent)
            {
                var recode = lstRecode.FirstOrDefault(p => p.RelationshipChildrenId == item.StudentId);
                if (recode != null)
                {
                    item.CompletionTime = recode.CreatedTime;
                    completeStudent.Add(item);
                }
                else
                {
                    unfinishedStudents.Add(item);
                }
            }
            result.Total = allStudent.Count;
            result.Completed = completeStudent.Count;
            result.CompleteStudent = completeStudent;
            result.UnfinishedStudents = unfinishedStudents;
            return result;
        }

        public class ParentChildTasksRecordByID : IEqualityComparer<ParentChildTasksRecord>
        {
            public bool Equals(ParentChildTasksRecord x, ParentChildTasksRecord y)
            {
                if (x == null || y == null)
                    return false;
                if (x.CreatedTime.Value.Date == y.CreatedTime.Value.Date)
                    return true;
                else
                    return false;
            }

            public int GetHashCode(ParentChildTasksRecord obj)
            {
                if (obj == null)
                    return 0;
                else
                    return obj.CreatedTime.Value.Date.GetHashCode();
            }
        }

        public List<DateTime> GetAllDay(DateTime start, DateTime end)
        {
            var result = new List<DateTime>();
            for (; start.Date <= end.Date; start = start.AddDays(1))
            {
                result.Add(start.Date);
            }
            return result;
        }

        private string GetFileSize(long size)
        {
            var num = 1024.00;
            if (size < num)
                return size + " B";
            if (size < Math.Pow(num, 2))
                return (size / num).ToString("f2") + " KB";
            if (size < Math.Pow(num, 3))
                return (size / Math.Pow(num, 2)).ToString("f2") + " MB";
            if (size < Math.Pow(num, 4))
                return (size / Math.Pow(num, 3)).ToString("f2") + " GB";
            return (size / Math.Pow(num, 4)).ToString("f2") + " TB";
        }

        public async Task<List<RecodeDto>> GetRecodeInfo(Guid TasksId)
        {
            var tasks = await _context.Set<ParentChildTasks>().Include(p => p.RecodeList).ThenInclude(p => p.Images).FirstOrDefaultAsync(p => p.Id == TasksId);
            if (tasks == null)
            {
                throw AppResultException.Status500InternalServerError("没有找到该亲子计划");
            }
            var alldate = GetAllDay(tasks.StartDate.Value, tasks.EndDate.Value);
            var totle = alldate.Count;
            var lstRecode = MapperHelper.Map<List<RecodeDto>>(tasks.RecodeList).OrderByDescending(p => p.CreatedTime).ToList();
            var lstParentId = lstRecode.Select(p => p.CreatedUserId).Distinct().ToList();
            var lstParent = _context.Set<Parent>().Where(p => lstParentId.Contains(p.Id)).ToList();

            foreach (var recode in lstRecode)
            {
                var parent = lstParent.FirstOrDefault(p => p.Id == recode.CreatedUserId);
                recode.ParentImgId = parent?.ImgId;
                recode.ClockInTimes = $"{recode.HowManyTimes}/{totle}";
            }
            return lstRecode.OrderBy(p => p.CreatedTime).ToList();
        }
    }
}
